// common/list_query.go
// =============================================================================
// | 包: common                                                               |
// | 模块: 列表查询                                                           |
// | 功能: 提供通用的分页查询功能，支持模糊查询、预加载和自定义条件            |
// =============================================================================
package common

import (
	"blog_server/global" // 全局变量包 - 提供全局配置和数据库连接

	"gorm.io/gorm" // ORM库 - 提供数据库操作功能
)

// =============================================================================
// | 结构体: PageInfo                                                         |
// | 功能: 定义分页查询的基本参数                                             |
// =============================================================================
type PageInfo struct {
	// -------------------------------------------------------------------------
	// | 字段: Limit - int                                                      |
	// | 功能: 每页显示的记录数量                                               |
	// | 映射: URL查询参数中的limit字段                                         |
	// -------------------------------------------------------------------------
	Limit int `form:"limit"` // 每页显示的记录数量

	// -------------------------------------------------------------------------
	// | 字段: Page - int                                                       |
	// | 功能: 当前页码                                                         |
	// | 映射: URL查询参数中的page字段                                          |
	// -------------------------------------------------------------------------
	Page int `form:"page"` // 当前页码

	// -------------------------------------------------------------------------
	// | 字段: Key - string                                                     |
	// | 功能: 搜索关键字，用于模糊匹配                                         |
	// | 映射: URL查询参数中的key字段                                           |
	// -------------------------------------------------------------------------
	Key string `form:"key"` // 搜索关键字

	// -------------------------------------------------------------------------
	// | 字段: Order - string                                                   |
	// | 功能: 排序规则，前端可以覆盖默认排序                                   |
	// | 映射: URL查询参数中的order字段                                         |
	// -------------------------------------------------------------------------
	Order string `form:"order"` // 排序规则
}

// =============================================================================
// | 结构体: Options                                                          |
// | 功能: 定义列表查询的选项参数                                             |
// =============================================================================
type Options struct {
	// -------------------------------------------------------------------------
	// | 字段: PageInfo - PageInfo                                              |
	// | 功能: 分页信息（包含页码、每页数量等）                                 |
	// -------------------------------------------------------------------------
	PageInfo PageInfo // 分页信息

	// -------------------------------------------------------------------------
	// | 字段: Likes - []string                                                 |
	// | 功能: 模糊查询字段列表（用于构建 LIKE 条件）                           |
	// -------------------------------------------------------------------------
	Likes []string // 模糊查询字段列表

	// -------------------------------------------------------------------------
	// | 字段: Preloads - []string                                              |
	// | 功能: 预加载关联字段列表（用于 GORM 的 Preload 关联查询）              |
	// -------------------------------------------------------------------------
	Preloads []string // 预加载关联字段列表

	// -------------------------------------------------------------------------
	// | 字段: Where - *gorm.DB                                                 |
	// | 功能: 高级查询条件                                                     |
	// -------------------------------------------------------------------------
	Where *gorm.DB // 高级查询条件

	// -------------------------------------------------------------------------
	// | 字段: Debug - bool                                                     |
	// | 功能: 是否开启调试模式                                                 |
	// -------------------------------------------------------------------------
	Debug bool // 调试模式开关

	// -------------------------------------------------------------------------
	// | 字段: DefaultOrder - string                                            |
	// | 功能: 默认排序规则                                                     |
	// -------------------------------------------------------------------------
	DefaultOrder string // 默认排序规则
}

// =============================================================================
// | 函数: GetPage                                                            |
// | 接收者: PageInfo                                                         |
// | 参数: 无                                                                  |
// | 返回: @int - 当前页码                                                    |
// | 功能: 获取当前页码，并进行安全校验                                       |
// | 说明: 页码范围限制在1-20之间                                             |
// |----------------------------------------------------------------------------|
// | 流程:                                                                     |
// | 1. 检查页码是否在有效范围内                                            |
// | 2. 如果超出范围则返回默认值1                                           |
// | 3. 否则返回原始页码                                                    |
// =============================================================================
func (p PageInfo) GetPage() int {
	// -------------------------------------------------------------------------
	// | 步骤1: 检查页码范围                                                    |
	// -------------------------------------------------------------------------
	// 检查页码是否在有效范围内(1-20)
	if p.Page > 20 || p.Page <= 0 {
		// 页码超出范围时返回默认值1
		return 1
	}

	// -------------------------------------------------------------------------
	// | 步骤2: 返回原始页码                                                    |
	// -------------------------------------------------------------------------
	// 返回原始页码
	return p.Page // 返回当前页码
}

// =============================================================================
// | 函数: GetLimit                                                           |
// | 接收者: PageInfo                                                         |
// | 参数: 无                                                                  |
// | 返回: @int - 每页记录数                                                  |
// | 功能: 获取每页记录数，并进行范围限制                                     |
// | 说明: 记录数范围限制在1-100之间                                          |
// |----------------------------------------------------------------------------|
// | 流程:                                                                     |
// | 1. 检查记录数是否在有效范围内                                          |
// | 2. 如果超出范围则返回默认值10                                          |
// | 3. 否则返回原始记录数                                                  |
// =============================================================================
func (p PageInfo) GetLimit() int {
	// -------------------------------------------------------------------------
	// | 步骤1: 检查记录数范围                                                  |
	// -------------------------------------------------------------------------
	// 检查记录数是否在有效范围内(1-100)
	if p.Limit <= 0 || p.Limit > 100 {
		// 记录数超出范围时返回默认值10
		return 10
	}

	// -------------------------------------------------------------------------
	// | 步骤2: 返回原始记录数                                                  |
	// -------------------------------------------------------------------------
	// 返回原始记录数
	return p.Limit // 返回每页记录数
}

// =============================================================================
// | 函数: GetOffset                                                          |
// | 接收者: PageInfo                                                         |
// | 参数: 无                                                                  |
// | 返回: @int - 分页偏移量                                                  |
// | 功能: 计算分页偏移量                                                     |
// | 说明: 偏移量 = (页码 - 1) * 每页记录数                                   |
// |----------------------------------------------------------------------------|
// | 流程:                                                                     |
// | 1. 调用GetPage获取当前页码                                             |
// | 2. 调用GetLimit获取每页记录数                                          |
// | 3. 计算并返回偏移量                                                    |
// =============================================================================
func (p PageInfo) GetOffset() int {
	// -------------------------------------------------------------------------
	// | 步骤1: 计算分页偏移量                                                  |
	// -------------------------------------------------------------------------
	// 计算分页偏移量: (页码 - 1) * 每页记录数
	return (p.GetPage() - 1) * p.GetLimit() // 返回分页偏移量
}

// =============================================================================
// | 函数: ListQuery                                                          |
// | 参数: @model - T (数据模型实例)                                          |
// |       @option - Options (查询选项)                                       |
// | 返回: @list - []T (查询结果列表)                                         |
// |       @count - int (总记录数)                                            |
// |       @err - error (错误信息)                                            |
// | 功能: 通用分页查询函数，支持模糊查询、预加载和自定义条件                 |
// | 说明: 使用泛型支持任意数据模型                                           |
// |----------------------------------------------------------------------------|
// | 流程:                                                                     |
// | 1. 构建基础查询条件                                                    |
// | 2. 应用调试模式                                                        |
// | 3. 应用模糊查询条件                                                    |
// | 4. 应用自定义查询条件                                                  |
// | 5. 应用预加载关联                                                      |
// | 6. 查询总记录数                                                        |
// | 7. 应用分页和排序                                                      |
// | 8. 执行查询并返回结果                                                  |
// =============================================================================
func ListQuery[T any](model T, option Options) (list []T, count int, err error) {
	// -------------------------------------------------------------------------
	// | 步骤1: 构建基础查询条件                                                |
	// -------------------------------------------------------------------------
	// 构建基础查询条件
	query := global.DB.Model(model).Where(model) // 基础查询条件

	// -------------------------------------------------------------------------
	// | 步骤2: 应用调试模式                                                    |
	// -------------------------------------------------------------------------
	// 检查是否开启调试模式
	if option.Debug {
		// 开启调试模式
		query = query.Debug() // 启用调试模式
	}

	// -------------------------------------------------------------------------
	// | 步骤3: 应用模糊查询条件                                                |
	// -------------------------------------------------------------------------
	// 检查是否有模糊查询字段且关键字不为空
	if len(option.Likes) > 0 && option.PageInfo.Key != "" {
		// 创建模糊查询条件
		likes := global.DB.Where("") // 初始化模糊查询条件

		// 遍历模糊查询字段
		for _, column := range option.Likes {
			// 使用参数化查询，避免SQL注入
			likes = likes.Or(column+" LIKE ?", "%"+option.PageInfo.Key+"%") // 添加模糊查询条件
		}

		// 将模糊查询条件合并到主查询
		query = query.Where(likes) // 合并模糊查询条件
	}

	// -------------------------------------------------------------------------
	// | 步骤4: 应用自定义查询条件                                              |
	// -------------------------------------------------------------------------
	// 检查是否有自定义查询条件
	if option.Where != nil {
		// 应用自定义查询条件
		query.Where(option.Where) // 应用自定义查询条件
	}

	// -------------------------------------------------------------------------
	// | 步骤5: 应用预加载关联                                                  |
	// -------------------------------------------------------------------------
	// 遍历预加载字段列表
	for _, preload := range option.Preloads {
		// 应用预加载关联
		query = query.Preload(preload) // 预加载关联模型
	}

	// -------------------------------------------------------------------------
	// | 步骤6: 查询总记录数                                                    |
	// -------------------------------------------------------------------------
	// 查询总记录数
	var _c int64
	global.DB.Model(model).Count(&_c) // 查询总记录数
	count = int(_c)                   // 转换为int类型

	// -------------------------------------------------------------------------
	// | 步骤7: 应用分页和排序                                                  |
	// -------------------------------------------------------------------------
	// 获取分页参数
	limit := option.PageInfo.GetLimit()   // 获取每页记录数
	offset := option.PageInfo.GetOffset() // 获取分页偏移量

	// 检查是否有自定义排序规则
	if option.PageInfo.Order != "" {
		// 应用自定义排序规则
		query = query.Order(option.PageInfo.Order) // 应用自定义排序
	} else {
		// 检查是否有默认排序规则
		if option.DefaultOrder != "" {
			// 应用默认排序规则
			query = query.Order(option.DefaultOrder) // 应用默认排序
		}
	}

	// -------------------------------------------------------------------------
	// | 步骤8: 执行查询并返回结果                                              |
	// -------------------------------------------------------------------------
	// 执行查询
	err = query.Offset(offset).Limit(limit).Find(&list).Error // 执行分页查询

	// -------------------------------------------------------------------------
	// | 步骤9: 返回查询结果                                                    |
	// -------------------------------------------------------------------------
	// 返回查询结果
	return // 返回结果列表、总记录数和错误信息
}
